﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.IO;

namespace TathamOddie.OpenSearchValidator.Logic
{
	public static class XsdValidator
	{
		public static Message[] Validate(string xml, string xsd)
		{
			var messages = new List<Message>();

			var schema = XmlSchema.Read(new StringReader(xsd), null);
			var document = new XmlDocument { PreserveWhitespace = true };

			document.Schemas.Add(schema);

			try
			{
				document.LoadXml(xml);
			}
			catch (XmlException ex)
			{
				messages.Add(new Message(MessageType.Failure, ex.Message));
				return messages.ToArray();
			}

			var expectedNamespace = schema.TargetNamespace;
			var actualNamespace = document.DocumentElement.NamespaceURI;
			if (!string.IsNullOrEmpty(expectedNamespace) &&
				!actualNamespace.Equals(expectedNamespace, StringComparison.Ordinal))
			{
				messages.Add(new Message(
					MessageType.Failure,
					string.IsNullOrEmpty(actualNamespace)
						? "Expected root XML node to have namespace of [{0}] but none was specified."
						: "Expected root XML node to have namespace of [{0}] but namespace was [{1}].",
					expectedNamespace,
					actualNamespace
				));

				document.DocumentElement.SetAttribute("xmlns", expectedNamespace);
				document.LoadXml(document.OuterXml);
			}

			document.Validate((s, a) =>
				{
					var messageType = a.Severity == XmlSeverityType.Error ? MessageType.Failure : MessageType.Warning;
					var messageText =
						a.Exception.LineNumber != 0
						? string.Format("Line {0}, position {1}: {2}", a.Exception.LineNumber, a.Exception.LinePosition, a.Message)
						: a.Message;
					messages.Add(new Message(messageType, messageText));
				});

			return messages.ToArray();
		}
	}
}